#pragma once
#include<iostream>
#include<mutex>
#include<thread>

using  namespace std;

namespace zjw
{
 template<class T>
 class auto_ptr
 {public:

 auto_ptr(T*ptr)
	 :_ptr(ptr)
 {

 }
 ~auto_ptr()
 {
	 if (_ptr)
	 {
		 cout << "delete :" << _ptr << endl;
		 delete _ptr;
	 

	 }
 
 }

 T* operator->()
 {
	 return _ptr;
 }
 T& operator*()
 {
 
	 return *_ptr;
 
 }
 auto_ptr(auto_ptr<T>&cp)
	 :_ptr(cp._ptr)
 {
	 cp._ptr = nullptr;
 
 }
 private:
	 T* _ptr;
 };
 


void test_auto_ptr()
 {
	auto_ptr<int>sp1(new int);
	auto_ptr<int>sp2(sp1);
	*sp1 = 1;
	*sp2 = 2;
 
 
 
 }
template <class T>
class unique_ptr
{
public:
	unique_ptr(T* ptr)
		:_ptr(ptr)
	{
	}
	~unique_ptr()
	{
		if (_ptr)
		{
			cout << "delete:" << _ptr << endl;
			delete _ptr;
		}
	
	
	
	}
	T& operator*()
	{
		return *_ptr;
	
	
	
	}
	T* operator->()
	{
		return _ptr;
	

	}
	unique_ptr(unique_ptr<T>& sp)=delete;
	unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;
//private:
//	unique_ptr(unique_ptr<T>& sp);
//	unique_ptr<T>& operator=(const unique_ptr<T>& sp);




private:
	T* _ptr;


};
void test_unique()
{

	unique_ptr<int>sp1(new int);
	//unique_ptr<int>sp2(sp1);





}
template <class T>
class share_ptr
{
public:
	share_ptr(T* ptr)
		:_ptr(ptr)
		, _pcount(new int(1))
		, _pmux(new mutex)
	{}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	int use_count()
	{
		return *_pcount;
	}
	T* get() const
	{

		return _ptr;


	}
	~share_ptr()
	{
		release();
	}
	void release()
	{
		_pmux->lock();

		if (--(*_pcount) == 0)
		{
			if (_ptr)
			{
				cout << "delete :" << _ptr << endl;
				delete _ptr;

			}


		}


		_pmux->unlock();


	}
	void addcount()
	{
		_pmux->lock();
		++(*_pcount);
		_pmux->unlock();
	}
	share_ptr(const share_ptr<T>& sp)
		:_ptr(sp._ptr)
		, _pcount(sp._pcount)
		,_pmux(sp._pmux)
	{
		addcount();

	}
	share_ptr<T>& operator=(const share_ptr<T>& sp)
	{
		if (_ptr != sp._ptr)
		{
			release();
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			_pmux = sp._pmux;
			addcount();
		}

		return *this;



	}

private:
	T* _ptr;
	int* _pcount;
	mutex* _pmux;




};

void test_share()
{
	share_ptr<int>sp1(new int(1));
	share_ptr<int>sp2(sp1);
	share_ptr<int>sp3(sp2);

	share_ptr<int>sp4(new int(1));

	sp4 = sp1;

}



struct date
{
	int _year = 0;
	int _month = 0;
	int _day = 0;
	~date()
	{
	
	
	}
};
void func(share_ptr<date>&sp,size_t n,mutex& mtx)
{

	for (int i = 0; i < n; i++)
	{   share_ptr<date>copy(sp);
		//mtx.lock();
		sp->_year++;
		sp->_month++;
		sp->_day++;
		//mtx.unlock();
	}
}
void test_share_safe()
{
	share_ptr<date> p(new date);
	cout << p.get() << endl;
	size_t n = 5000;
	mutex mux;
	thread t1(func, ref(p), n,ref(mux));
	thread t2(func, ref(p), n, ref(mux));


	t1.join();
	t2.join();
	
	cout << p.use_count() << endl;


	cout << p->_year << endl;
	cout << p->_month << endl;
	cout << p->_day << endl;

}














}
